package com.feimt.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.feimt.dto.SetmealDto;
import com.feimt.pojo.Category;
import com.feimt.pojo.Dish;
import com.feimt.pojo.Setmeal;
import com.feimt.pojo.SetmealDish;
import com.feimt.result.R;
import com.feimt.service.CategoryService;
import com.feimt.service.DishService;
import com.feimt.service.SetmealDishService;
import com.feimt.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 宋孟林
 * @description
 */
@RestController
@Slf4j
@RequestMapping("/setmeal")
public class SetmealController {
    private SetmealService setMealService;
    private CategoryService categoryService;
    private SetmealDishService setmealDishService;
    private DishService dishService;

    @Autowired
    public SetmealController(SetmealService setMealService, CategoryService categoryService, SetmealDishService setmealDishService, DishService dishService) {
        this.setMealService = setMealService;
        this.categoryService = categoryService;
        this.setmealDishService = setmealDishService;
        this.dishService = dishService;
    }

    /**
     * 分页查询套餐信息及其分类名称。
     * 此方法根据分页参数和可选的套餐名称过滤条件，查询套餐的分页数据。
     * 查询结果不仅包含套餐的基本信息，还会附加每个套餐对应的分类名称。
     * @param page 当前页码（从 1 开始）
     * @param pageSize 每页记录数
     * @param name （可选）套餐名称，用于模糊查询
     * @return 返回包含分页套餐信息及分类名称的响应结果 {@link R}，其中包含分页对象 {@link Page} 包装的套餐数据 {@link SetmealDto}
     * 方法逻辑：
     * 1. 创建 `Page<Setmeal>` 和 `Page<SetmealDto>` 用于存储分页数据。
     * 2. 构造查询条件（基于套餐名称的模糊查询和更新时间降序排序）。
     * 3. 调用 `setMealService.page` 方法查询分页套餐数据。
     * 4. 复制基础分页属性（如总页数、总记录数等）到目标分页对象 `setmealDtoPage`。
     * 5. 遍历分页数据记录，将每条 `Setmeal` 转换为 `SetmealDto`，并通过 `categoryService` 获取分类名称。
     * 6. 将转换后的记录设置到目标分页对象中并返回成功响应。
     */
    @GetMapping("/page")
    public R<Page<SetmealDto>> page(Integer page, Integer pageSize, String name){
        Page<Setmeal> pageInfo = new Page<>(page, pageSize);
        Page<SetmealDto> setmealDtoPage = new Page<>();
        LambdaQueryWrapper<Setmeal> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(name != null, Setmeal::getName, name);
        wrapper.orderByDesc(Setmeal::getUpdateTime);
        setMealService.page(pageInfo, wrapper);
        BeanUtils.copyProperties(pageInfo, setmealDtoPage, "records");
        List<Setmeal> records = pageInfo.getRecords();
        List<SetmealDto> list = records.stream().map((item) -> {
            SetmealDto setmealDto = new SetmealDto();
            BeanUtils.copyProperties(item, setmealDto);
            Long categoryId = item.getCategoryId();
            Category category = categoryService.getById(categoryId);
            if (category != null) {
                String categoryName = category.getName();
                setmealDto.setCategoryName(categoryName);
            }
            return setmealDto;
        }).collect(Collectors.toList());
        setmealDtoPage.setRecords(list);
        return R.success(setmealDtoPage);
    }

    /**
     * 传入setmealdto对象使用自定义的保存套餐的方法来实现新增套餐
     * @param setmealDto d
     * @return 前端信息
     */
    @PostMapping
    public R<String> save(@RequestBody SetmealDto setmealDto){
        log.info("setmealDto: {}", setmealDto);
        boolean flag = setMealService.saveWithDish(setmealDto);
        return flag ? R.success("新增套餐成功") : R.error("新增套餐失败");
    }

    /**
     * 根据id和自定义的回显setmeal的方法来回显套餐dto数据
     * @param id id
     * @return 前端展示
     */
    @GetMapping("/{id}")
    public R<SetmealDto> echoSetMeal(@PathVariable Long id){
        log.info("回显的套餐数据id为：{}", id);
        SetmealDto setmealDto = setMealService.getData(id);
        return R.success(setmealDto);
    }

    /**
     * 更新套餐信息该方法用于更新套餐信息，包括更新套餐的菜品列表。它接受一个 `SetmealDto` 对象，其中包含套餐的详细信息，
     * 并在更新套餐的同时清理和更新关联的菜品数据。
     * 处理流程如下：
     * 1. 检查传入的 `setmealDto` 是否为 `null`，如果是则返回错误信息。
     * 2. 检查套餐中的菜品是否为 `null`，如果没有菜品则返回错误信息。
     * 3. 获取套餐的 ID 和菜品列表。
     * 4. 删除与该套餐 ID 关联的所有菜品记录。
     * 5. 为每个菜品设置正确的套餐 ID。
     * 6. 批量保存新的菜品记录。
     * 7. 更新套餐本身的信息。
     * 8. 返回成功信息。
     * @param setmealDto 包含套餐及其菜品数据的 DTO 对象
     * @return 返回操作结果，成功则返回 `R.success`，失败则返回 `R.error`
     */
    @PutMapping
    public R<String> update(@RequestBody SetmealDto setmealDto){
        log.info("semealDto: {}", setmealDto);
        if (setmealDto == null){
            return R.error("请求异常");
        }
        if (setmealDto.getSetmealDishes() == null){
            return R.error("套餐没有菜品,请添加套餐");
        }
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        Long setmealId = setmealDto.getId();
        LambdaQueryWrapper<SetmealDish> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SetmealDish::getSetmealId, setmealId);
        setmealDishService.remove(wrapper);
        for (SetmealDish setmealDish : setmealDishes) {
            setmealDish.setSetmealId(setmealId);
        }
        setmealDishService.saveBatch(setmealDishes);
        setMealService.updateById(setmealDto);
        return R.success("套餐修改成功");
    }

    /**
     * 修改单个套餐和多个套餐的启售和停售问题
     * @param s 应该设置的状态
     * @param ids 应该改变状态的套餐id
     * @return 返回前端信息
     */
    @PostMapping("/status/{s}")
    public R<String> updateStatus(@PathVariable Integer s, @RequestParam List<Long> ids){
        log.info("修改的id为： {}", ids);
        LambdaUpdateWrapper<Setmeal> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(Setmeal::getId, ids).set(Setmeal::getStatus, s);
        boolean b = setMealService.update(wrapper);
        return b ? R.success("修改成功") : R.error("修改失败");
    }

    /**
     * 根据id删除套餐
     * @param ids 根据id删除
     * @return 返回前端信息
     */
    @DeleteMapping
    public R<String> delete(@RequestParam List<Long> ids){
        log.info("删除的ids有：{}", ids);
        boolean b = setMealService.deleteWithDish(ids);
        return b ? R.success("删除成功") : R.error("删除失败");
    }

    /**
     * 显示套餐信息
     * @param setmeal 套餐对象
     * @return 返回套餐集合
     */
    @GetMapping("/list")
    public R<List<Setmeal>> list(Setmeal setmeal){
        log.info("套餐信息为： {}", setmeal);
        LambdaQueryWrapper<Setmeal> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId()).eq(Setmeal::getStatus, 1);
        wrapper.orderByDesc(Setmeal::getUpdateTime);
        List<Setmeal> setmealList = setMealService.list(wrapper);
        return R.success(setmealList);
    }

    /**
     * 展示菜品
     * @param id 展示的菜品id
     * @return 返回菜品对象集合
     */
    @GetMapping("/dish/{id}")
    public R<List<SetmealDish>> dish(@PathVariable Long id){
        log.info("需要展示的菜品id为：{}", id);
        LambdaQueryWrapper<SetmealDish> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SetmealDish::getId, id);
        List<SetmealDish> setmealDishList = setmealDishService.list(wrapper);
        setmealDishList = setmealDishList.stream().map(item ->{
            Dish dish = dishService.getById(item.getId());
            item.setImage(dish.getImage());
            return item;
        }).collect(Collectors.toList());
        return R.success(setmealDishList);
    }
}
